
#pragma once

const int nImageMargin = 4;
const int nBorderMarginX = 1;
const int nBorderMarginY = 3;


#ifndef max
#define max(a,b) (((a) > (b))?(a):(b))
#endif

class CGalleryEx: public CMFCRibbonGallery
{
public:
    CGalleryEx() : CMFCRibbonGallery() {m_nPanelColumns = 2;};
	CGalleryEx(UINT nID, LPCTSTR lpszText, int nSmallImageIndex, int nLargeImageIndex, CMFCToolBarImages& imagesPalette) : CMFCRibbonGallery(nID, lpszText, nSmallImageIndex, nLargeImageIndex, imagesPalette) {m_nPanelColumns = 2;};
	CGalleryEx(UINT nID, LPCTSTR lpszText, int nSmallImageIndex, int nLargeImageIndex, UINT uiImagesPaletteResID = 0, int cxPaletteImage = 0) : CMFCRibbonGallery(nID, lpszText, nSmallImageIndex, nLargeImageIndex, uiImagesPaletteResID, cxPaletteImage) {m_nPanelColumns = 2;};
	virtual ~CGalleryEx() {};
protected:
	virtual void StretchHorizontally()
	{
		if (m_bSmallIcons || m_nPanelColumns < 2)
		{
			m_bIsCollapsed = TRUE;
		}
		else
		{
			m_nPanelColumns--;
		}
	};
	virtual CSize GetRegularSize(CDC* pDC)
	{
		ASSERT_VALID(this);

		const CSize sizeImage = GetIconSize();
		CSize sizePanelSmallImage(16, 16);

		if (m_pParent != NULL)
		{
			ASSERT_VALID(m_pParent);
			sizePanelSmallImage = m_pParent->GetImageSize(FALSE);
		}

		m_bSmallIcons = (sizeImage.cx <= sizePanelSmallImage.cx * 3 / 2);

		if (m_bResetColumns && !m_bSmallIcons)
		{
			m_nPanelColumns = 1;

			if (m_pParentMenu != NULL && m_pParentMenu->GetCategory() == NULL)
			{
				// From the default panel button
				m_nPanelColumns = 1;
			}
		}

		m_bResetColumns = FALSE;

		if (IsButtonLook())
		{
			return CMFCRibbonButton::GetRegularSize(pDC);
		}

		if (m_arIcons.GetSize() == 0)
		{
			CreateIcons();
		}

		ASSERT_VALID(m_pParent);

		const CSize sizePanelLargeImage = m_pParent == NULL ? 
			CSize (0, 0) : m_pParent->GetImageSize(TRUE);

		CSize size(0, 0);

		if (m_bSmallIcons)
		{
			size.cx = sizeImage.cx * m_nPanelColumns;

			int nRows = 3;

			if (sizePanelLargeImage != CSize(0, 0) && sizeImage.cy != 0)
			{
				nRows = max(nRows, sizePanelLargeImage.cy * 2 / sizeImage.cy);
			}

			size.cy = nRows * sizeImage.cy + 2 * nBorderMarginY;
		}
		else
		{
			size.cx = (sizeImage.cx + 2 * nImageMargin) * m_nPanelColumns;
			size.cy = sizeImage.cy + 3 * nImageMargin + 2 * nBorderMarginY;
		}

		//---------------------------------------
		// Add space for menu and scroll buttons:
		//---------------------------------------
		size.cx += GetDropDownImageWidth() + 3 * nImageMargin;

		return size;
	};

};

class CMFCPropertyGridCtrlEx : public CMFCPropertyGridCtrl
{
public:
    CMFCPropertyGridCtrlEx() : CMFCPropertyGridCtrl()  {};

    void RemoveAll()
	{
	 ASSERT_VALID(this);

	 while (!m_lstProps.IsEmpty())
	 {
		m_lstProps.RemoveHead();
	 }

	 while (m_nTooltipsCount > 0)
	 {
		m_ToolTip.DelTool(this, m_nTooltipsCount);
		m_nTooltipsCount--;
	 }

	 m_lstTerminalProps.RemoveAll();

	 m_pSel = NULL;
	};
};

class CExMFCPropertyGridProperty: public CMFCPropertyGridProperty
{
public:
	CExMFCPropertyGridProperty(const CString& strGroupName, DWORD_PTR dwData = 0, BOOL bIsValueList = FALSE, CString FloatFormat = _T("%.2f"), BOOL bIsComplexParent = FALSE):CMFCPropertyGridProperty(strGroupName,dwData, bIsValueList) {m_strFloatFormat = FloatFormat;m_ComplexParent = bIsComplexParent;};

	// Simple property
	CExMFCPropertyGridProperty(const CString& strName, const COleVariant& varValue, LPCTSTR lpszDescr = NULL, DWORD_PTR dwData = 0, CString FloatFormat = _T("%.2f"),
		LPCTSTR lpszEditMask = NULL, LPCTSTR lpszEditTemplate = NULL, LPCTSTR lpszValidChars = NULL):CMFCPropertyGridProperty(strName,varValue,lpszDescr,dwData,lpszEditMask, lpszEditTemplate, lpszValidChars) {m_strFloatFormat = FloatFormat;m_ComplexParent = FALSE;};

    inline BOOL IsComplexParent() {return m_ComplexParent;};
protected:
	CString m_strFloatFormat;
	BOOL    m_ComplexParent;
    AlignedObjectArray<CExMFCPropertyGridProperty*> UpdateList;
 
	virtual BOOL TextToVar(const CString& strText)
	{
		CString strVal = strText;

		switch (m_varValue.vt)
		{
		case VT_R4:
			{
				float fVal = 0.0f;
				strVal.TrimLeft();
				strVal.TrimRight();
				if (!strVal.IsEmpty())
				{
					_stscanf_s(strVal, _T("%f"), &fVal);
				}
				m_varValue = fVal;
			}
			return TRUE;
		case VT_I4:
		case VT_INT:
			{
			    long iVal = 0;
				strVal.TrimLeft();
				strVal.TrimRight();
				if (!strVal.IsEmpty())
				{
					_stscanf_s(strVal, _T("%d"), &iVal);
				}
				m_varValue = iVal;
				m_varValue.ChangeType(VT_INT);
			}
			return TRUE;
		default:
			return CMFCPropertyGridProperty::TextToVar(strText);
		}
		return FALSE;
	};
    
	virtual CString FormatProperty()
    {
	  ASSERT_VALID(this);
	  ASSERT_VALID(m_pWndList);

	  COleVariant& var = m_varValue;

	  CString strVal;

	  if (m_bIsValueList)
	  {
		  return CMFCPropertyGridProperty::FormatProperty();
	  }

	  switch (var.vt)
	  {
	  case VT_R4:
		  strVal.Format(m_strFloatFormat, (float)var.fltVal);
		  break;

	  default:
		  return CMFCPropertyGridProperty::FormatProperty();
	  }

	  return strVal;
  };
  virtual BOOL OnUpdateValue()
  {
	ASSERT_VALID(this);
	ASSERT_VALID(m_pWndInPlace);
	ASSERT_VALID(m_pWndList);
	ASSERT(::IsWindow(m_pWndInPlace->GetSafeHwnd()));

	CString strText;
	m_pWndInPlace->GetWindowText(strText);
    
    if (m_bIsValueList)
	{
	  BOOL bRes = FALSE;
	  BOOL bIsChanged = FormatProperty() != strText;

	  CString strDelimeter(_T(","));
	  UpdateList.clear();

	  for (int i = 0; !strText.IsEmpty() && i < GetSubItemsCount(); i++)
	  {
	   	CString strItem = strText.SpanExcluding(strDelimeter);

	  	if (strItem.GetLength() + 1 > strText.GetLength())
		{
			strText.Empty();
		}
		else
		{
			strText = strText.Mid(strItem.GetLength() + 1);
		}

		strItem.TrimLeft();
		strItem.TrimRight();

		CExMFCPropertyGridProperty* pSubItem = static_cast<CExMFCPropertyGridProperty*>(GetSubItem(i));
		ASSERT_VALID(pSubItem);

  	    BOOL bSubChanged = pSubItem->TextToVar(strItem);
		
        if (bSubChanged && bIsChanged && !m_ComplexParent)
	    {
		  UpdateList.push_back(pSubItem);
	    }
	  }
	  
      for(unsigned int i = 0;i < UpdateList.size();i++) m_pWndList->OnPropertyChanged(UpdateList[i]);      
   	  
      if(m_ComplexParent)
          m_pWndList->OnPropertyChanged(this);

      return TRUE;
    }
	else 
    {
        CExMFCPropertyGridProperty *parentprop = dynamic_cast<CExMFCPropertyGridProperty*>(GetParent());
        if(parentprop && parentprop->IsComplexParent())
        {
            TextToVar(strText);
            m_pWndList->OnPropertyChanged(GetParent());
            return TRUE;
        }
        else
            return CMFCPropertyGridProperty::OnUpdateValue();
    }
  };
  virtual void OnDrawName(CDC* pDC, CRect rect)
  {
	CExMFCPropertyGridProperty *parent = static_cast<CExMFCPropertyGridProperty*>(m_pParent);
	if(parent != NULL && parent->m_bIsValueList)
	{
		rect.left -= rect.Height();
	}
	CMFCPropertyGridProperty::OnDrawName(pDC,rect);
  };
};
//------------------------------------------------------------------------------
/// We derive our own edit control class for password editing
class CMFCRibbonEditPassword: public CMFCRibbonEdit
{
public:
	CMFCRibbonEditPassword(UINT nID, int nWidth, LPCTSTR lpszLabel = NULL, int nImage = -1)
		: CMFCRibbonEdit(nID, nWidth, lpszLabel, nImage) {}
	CMFCRibbonRichEditCtrl *CreateEdit(CWnd *pWndParent, DWORD dwEditStyle)
		{ dwEditStyle |= ES_PASSWORD; return CMFCRibbonEdit::CreateEdit(pWndParent, dwEditStyle); }
};
